"""
The MIT License

Copyright (c) 2008

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Author: Eric Van Dewoestine
"""
import httplib, re

from myspace.oauth import oauth

class MockProxy (object):
  """
  Mock proxy intended to similuate a request coming from the myspace proxy.

  This class is designed to allow you to simulate a gadgets.io.makeRequest call
  to your server.
  """
  RE_URI = re.compile(r'http://[^/]*')

  def __init__ (self, key, secret, server='localhost', port=80):
    """
    Initializes the client.

    @param key: The oauth consumer key. In MySpace terms, the "Application
    Uri".
    @param secret: The oauth consumer secret. In MySpace terms, the "Security
    Key".
    @param server: The hostname of the server to send the request to. (Defaults
    to 'locahost')
    @param port: The port to send the request to. (Defaults to 80)
    """
    self.key = key
    self.secret = secret
    self.server = server
    self.port = port

  def makeRequest (self, uri,
      method='GET', authorization='SIGNED', post_data=None, viewer_id=-1):
    """
    Initializes a mock proxy using the supplied uri to send the request to.

    @param uri: The uri to send the request to.
    @param method: The http method to use (Defaults to 'GET').
    Only 'GET' and 'POST' are supported.
    @param authorization: The authorization type to use (Defaults to 'SIGNED').
    Currently only 'SIGNED' supported.
    @param post_data: Dictionary including any post data to be sent.
    @param viewer_id: The myspace id of the viewer to simulate the request
    coming from (Defaults to -1, which is what myspace uses for anonymous users).
    """
    consumer = oauth.OAuthConsumer(self.key, self.secret)
    token = oauth.OAuthToken('', '')
    signature_method = oauth.OAuthSignatureMethod_HMAC_SHA1()
    url = 'http://%s%s' % (
      self.port == 80 and self.server or '%s:%s' % (self.server, self.port),
      uri
    )
    params = post_data or {}
    if viewer_id:
      params['opensocial_viewer_id'] = viewer_id

    oauth_request = oauth.OAuthRequest.from_consumer_and_token(
      consumer, token=token, http_method=method, http_url=url, parameters=params
    )
    oauth_request.sign_request(signature_method, consumer, None)

    connection = httplib.HTTPConnection('%s:%s' % (self.server, self.port))

    body, headers = None, None
    if method in ('POST', 'PUT'):
      body = oauth_request.to_postdata()
      headers = {'Content-Type': 'text/plain'}
      url = MockProxy.RE_URI.sub('', oauth_request.to_url())
      connection.request(
        oauth_request.http_method,
        url,
        body=body,
        headers=headers,
        #headers=oauth_request.to_header() # this caused invalid signature errors.
      )
    else:
      url = MockProxy.RE_URI.sub('', oauth_request.to_url())
      connection.request(
        oauth_request.http_method,
        url,
        #headers=oauth_request.to_header() # this caused invalid signature errors.
      )
    response = connection.getresponse()
    if response.status != 200:
      raise MockProxyError(response.status, response.reason, response.read())
    return response.read()


class MockProxyError (Exception):
  """
  Error class used to raise errors received by the mock proxy.
  """

  def __init__ (self, status, reason, response):
    self.status = status
    self.reason = reason
    self.response = response

  def __str__ (self):
    return '%s: %s' % (self.status, self.reason)
